package com.kunlun.gateway.filter;

import com.kunlun.common.model.ClientToken;
import com.kunlun.common.model.SignTokenModel;
import com.kunlun.common.utils.JwtTokenUtil;
import com.kunlun.gateway.model.ShiroConfigModel;
import com.kunlun.gateway.rpc.FeignBasedataService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Map;

/**
 * shiro过滤器，认证token
 */
@Component
public class AuthenticationFilter implements GlobalFilter, Ordered {

    private Logger log = LogManager.getLogger();

    @Autowired
    private ShiroConfigModel shiroConfigModel;
    @Autowired
    private FeignBasedataService basedataService;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 访问URL过滤
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String requestUrl = String.valueOf(request.getPath());
        if (shiroConfigModel.getIgnoreUrls().contains(requestUrl)) {
            return chain.filter(exchange);
        }

        // 账号校验
        if (verifyAccount(request, response)) {
            return chain.filter(exchange);
        }
        return response.setComplete();
    }

    private boolean verifyAccount(ServerHttpRequest request, ServerHttpResponse response) {
        log.info("Start ShiroFilter executeLogin");

        // Token校验
        String token = request.getHeaders().getFirst(shiroConfigModel.getTokenHeader());
        ClientToken clientToken = JwtTokenUtil.getClientToken(token);
        String redisKey = clientToken.getUserName() + "_" + clientToken.getLoginTime();
        Map<String, Object> map = (Map<String, Object>) basedataService.get(redisKey, 1);
        String refreshedToken = (String) map.get("data");
        boolean jwt = JwtTokenUtil.verify(refreshedToken, clientToken.getUserName(), clientToken.getPassword(), shiroConfigModel.getSecret());
        if (jwt) {
            // 用户在线操作，Token续期
            // 此处不能刷新即续期token，否则新的token无法传递到前台，无法保持全局一致；此处不能校验token是否有效，因刷新或续期token无法处理
            log.info("token ===>>> " + token);
            SignTokenModel signToken = new SignTokenModel(clientToken, shiroConfigModel.getSecret(), shiroConfigModel.getExpireTime());
            String shiroToken = JwtTokenUtil.sign(signToken);
            log.info("update token ===>>> " + shiroToken);
            basedataService.set(redisKey, shiroToken, shiroConfigModel.getExpireTime(), 1);
            return true;
        } else {
            // Token过期后，前台提示用户，并阻止向下游服务继续调用
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            response.setRawStatusCode(999);
            log.info("离开时间太长，请重新登录！");
            return false;
        }
    }

    @Override
    public int getOrder() {
        return 1;
    }
}
